﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MethodWorx.CMS.TemplateLanguage.Properties;
using MethodWorx.CMS.TemplateLanguage.Design;
using MethodWorx.CMS.Services;
using MethodWorx.CMS.Content;
using MethodWorx.CMS.Plugins.ViewManagement;
using MethodWorx.CMS.Providers;
using MethodWorx.CMS.Web;

namespace MethodWorx.CMS.TemplateLanguage.Parsers.Content
{
    public class Repeater : IParser, IDesignable, IMetaParser
    {
        [Property]
        public string Tags { get; set; }

        [Property]
        public string View { get; set; }

        [DependencyPropertyAttribute]
        public ContentService ContentService { get; set; }

        [DependencyPropertyAttribute]
        public ICmsDataProvider Provider { get; set; }

        [Property]
        public bool Inline { get; set; }

        [ContentTemplateProperty]
        public string Template { get; set; }

        [Property]
        public int? Maximum { get; set; }

        [Property]
        public string OrderBy { get; set; }

        [Property]
        public string OrderDirection { get; set; }

        [Property]
        public string Options { get; set; }

        [Property(Description = "Set an arbitrary break index to allow template customization at the item index")]
        public int? BreakIndex { get; set; }

        public object Parse(Web.CmsRequestContext context, IEnumerable<object> stack, Dictionary<string, object> parameters)
        {
            List<EnumerableResult> results = new List<EnumerableResult>();
            var currentPage = stack.OfType<MethodWorx.CMS.Content.Page>().FirstOrDefault();

            int i = 1;
            List<string> names = new List<string>();
            var items = this.GetContentItem(currentPage, context).OrderBy(c => c.DateCreated).ToList();
            if (items.Count == 0)
            {
                results.Add(new EnumerableResult()
                {
                    Names = new string[] { "empty" },
                    Result = new object()
                });
            }
            else
            {
                foreach (var contentItem in items)
                {
                    names.Add("default");
                    names.Add("index" + i);
                    if (i % 2 == 0)
                        names.Add("even");
                    else
                        names.Add("odd");

                    if (this.BreakIndex.HasValue)
                    {
                        if (i % this.BreakIndex.Value == 0)
                            names.Add("break");
                    }


                    results.Add(new EnumerableResult()
                    {
                        Names = names.ToArray(),
                        Results = new object[] { contentItem.Page, contentItem }
                    });

                    names.Clear();

                    i++;
                }
            }

            return results;
        }

        private IEnumerable<ContentItem> GetContentItem(MethodWorx.CMS.Content.Page page, Web.CmsRequestContext context)
        {
            if (!string.IsNullOrEmpty(this.View))
            {
                var service = new StaticViewService(this.Provider);
                foreach (var sv in service.GetAll())
                {
                    if (sv.Name.ToLower() == this.View.ToLower())
                    {
                        //
                        //  ok, this is the view
                        foreach (Guid id in sv.Ids ?? new Guid[0])
                        {
                            var contentItem = this.ContentService.GetContentItemById(id);
                            if (contentItem != null && CheckStatus(context, contentItem))
                                yield return contentItem;
                        }
                    }
                }
            }
            else if (!string.IsNullOrEmpty(this.Tags))
            {
                foreach (var contentItem in this.ContentService.GetContentItemsByTags(this.Tags).OrderBy(c => c.Sequence))
                    yield return contentItem;
            }
            else
            {
                //
                //  ok, we are falling back to a querying method
                if(!string.IsNullOrEmpty(this.Template))
                {
                    ContentQueryOptions options = ContentQueryOptions.None;
                    try
                    {
                        options = (ContentQueryOptions)Enum.Parse(typeof(ContentQueryOptions), this.Options);
                    }
                    catch
                    {
                    }
                    //
                    // lets find
                    foreach (var contentItem in this.ContentService.GetContentByTemplate(page, this.Template, this.OrderBy, this.OrderDirection, this.Maximum, context.Preview, options).OrderBy(c => c.Sequence))
                    {
                        //
                        //  ok, so far so good, lets return them
                        yield return contentItem;
                    }
                }
            }
        }

        private bool CheckStatus(CmsRequestContext context, ContentItem contentItem)
        {
            if(context.Preview)
            {
                return contentItem.Status == ContentStatus.Unpublished ||
                       contentItem.Status == ContentStatus.Published;
            }
            else
            {
                return contentItem.Status == ContentStatus.Published ||
                       contentItem.Status == ContentStatus.PublishedAndAwaitingDelete;
            }
        }

        public string Name
        {
            get { return "Repeater";  }
        }

        public string Namespace
        {
            get { return "Content"; }
        }

        public void Design(IDesigner designer)
        {
            var control = designer.AddControl("Content:Repeater");
            control.AddChildControl("default")
                .AddChildControl("notexists");
        }

        public string GetDescription()
        {
            return "Enumerates all matching content items from a set of filters";
        }

        public ParserMetaParameter[] GetParameters(Stack<object> stack, ParserMetaParameter[] parameters)
        {
            return parameters;
        }
    }
}
